import org.bytedeco.javacv.*;
import org.bytedeco.opencv.opencv_core.Mat;
import javax.sip.*;
import javax.sip.address.*;
import javax.sip.header.*;
import javax.sip.message.*;
import java.net.InetAddress;
import java.util.*;
import java.util.concurrent.*;

/**
 * RTSP流转GB28181协议网关
 * 拉取RTSP流并封装为GB28181协议发送给国标平台
 */
public class RtspToGb28181Gateway implements SipListener {
    // 配置参数
    private final String rtspUrl;
    private final String localIp;
    private final int localPort;
    private final String ssrc;
    private final String国标平台Ip;
    private final int国标平台Port;
    private final String deviceId; // 设备ID（GB28181规定的编码）
    private final String channelId; // 通道ID

    // 信令相关
    private SipFactory sipFactory;
    private SipStack sipStack;
    private SipProvider sipProvider;
    private AddressFactory addressFactory;
    private MessageFactory messageFactory;
    private HeaderFactory headerFactory;

    // 媒体处理
    private FrameGrabber grabber;
    private ScheduledExecutorService executor;
    private volatile boolean isRunning = false;

    public RtspToGb28181Gateway(String rtspUrl, String localIp, int localPort,
                               String国标平台Ip, int国标平台Port,
                               String deviceId, String channelId) {
        this.rtspUrl = rtspUrl;
        this.localIp = localIp;
        this.localPort = localPort;
        this.国标平台Ip = 国标平台Ip;
        this.国标平台Port = 国标平台Port;
        this.deviceId = deviceId;
        this.channelId = channelId;
        this.ssrc = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
        
        try {
            initSipStack();
        } catch (Exception e) {
            throw new RuntimeException("初始化SIP协议栈失败", e);
        }
    }

    /**
     * 初始化SIP协议栈（GB28181基于SIP协议）
     */
    private void initSipStack() throws Exception {
        sipFactory = SipFactory.getInstance();
        sipFactory.setPathName("gov.nist");
        
        Properties properties = new Properties();
        properties.setProperty("javax.sip.STACK_NAME", "GB28181Gateway-" + deviceId);
        properties.setProperty("javax.sip.IP_ADDRESS", localIp);
        
        sipStack = sipFactory.createSipStack(properties);
        addressFactory = sipFactory.createAddressFactory();
        messageFactory = sipFactory.createMessageFactory();
        headerFactory = sipFactory.createHeaderFactory();
        
        // 创建SIP监听点
        ListeningPoint listeningPoint = sipStack.createListeningPoint(localPort, "UDP");
        sipProvider = sipStack.createSipProvider(listeningPoint);
        sipProvider.addSipListener(this);
    }

    /**
     * 启动网关
     */
    public void start() {
        isRunning = true;
        executor = Executors.newScheduledThreadPool(2);
        
        // 启动RTSP拉流线程
        executor.execute(this::startRtspGrabber);
        
        // 发送注册消息到国标平台
        try {
            sendRegisterRequest();
        } catch (Exception e) {
            System.err.println("发送注册消息失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 开始拉取RTSP流
     */
    private void startRtspGrabber() {
        try {
            // 初始化RTSP抓取器
            grabber = FrameGrabber.createDefault(rtspUrl);
            grabber.setOption("rtsp_transport", "tcp");
            grabber.start();
            
            System.out.println("RTSP流拉取成功: " + rtspUrl);
            System.out.println("视频信息 - 宽度: " + grabber.getImageWidth() + 
                               ", 高度: " + grabber.getImageHeight() +
                               ", 帧率: " + grabber.getFrameRate());

            // 处理视频帧并发送
            processFrames();
            
        } catch (Exception e) {
            System.err.println("RTSP拉流失败: " + e.getMessage());
            e.printStackTrace();
        } finally {
            stop();
        }
    }

    /**
     * 处理视频帧并封装为GB28181协议发送
     */
    private void processFrames() throws Exception {
        Frame frame;
        long timestamp = 0;
        int seq = 0;
        
        // 发送INVITE请求建立媒体会话
        sendInviteRequest();
        
        while (isRunning && (frame = grabber.grab()) != null) {
            // 转换为H.264帧（GB28181通常使用H.264编码）
            byte[] h264Data = convertToH264(frame);
            
            if (h264Data != null) {
                // 封装为RTP包（GB28181使用RTP传输媒体数据）
                byte[] rtpPacket = encapsulateToRtp(h264Data, seq++, timestamp);
                
                // 发送RTP包到国标平台
                sendRtpPacket(rtpPacket);
                
                // 更新时间戳（根据帧率计算）
                timestamp += 90000 / (int)grabber.getFrameRate(); // 90000是H.264的时钟频率
            }
            
            // 控制发送速率
            Thread.sleep(40); // 大约25fps，可根据需要调整
        }
    }

    /**
     * 转换帧数据为H.264格式
     */
    private byte[] convertToH264(Frame frame) {
        // 实际项目中需要根据源视频编码进行转换
        // 这里简化处理，实际需要使用编码器进行转码
        try (Java2DFrameConverter converter = new Java2DFrameConverter()) {
            // 此处仅为示例，实际需要正确的H.264编码实现
            return new byte[0];
        }
    }

    /**
     * 封装H.264数据为RTP包
     */
    private byte[] encapsulateToRtp(byte[] h264Data, int sequenceNumber, long timestamp) {
        // RTP头部结构: 版本(2) + 填充(1) + 扩展(1) + CSRC计数(4) +
        // 标记(1) + 载荷类型(7) + 序列号(16) + 时间戳(32) + SSRC(32)
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        DataOutputStream dataOut = new DataOutputStream(out);
        
        try {
            // RTP版本为2，其他字段默认
            dataOut.writeByte((byte)0x80); 
            // 载荷类型：96表示动态RTP载荷
            dataOut.writeByte((byte)0x60); 
            // 序列号
            dataOut.writeShort(sequenceNumber);
            // 时间戳
            dataOut.writeInt((int)timestamp);
            // SSRC
            dataOut.writeInt(Integer.parseInt(ssrc, 16));
            // H.264数据
            dataOut.write(h264Data);
            
            return out.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 发送RTP包到国标平台
     */
    private void sendRtpPacket(byte[] rtpPacket) {
        // 使用UDP发送RTP包到国标平台的媒体端口
        try (DatagramSocket socket = new DatagramSocket()) {
            InetAddress address = InetAddress.getByName(国标平台Ip);
            DatagramPacket packet = new DatagramPacket(rtpPacket, rtpPacket.length, 
                                                     address, 国标平台Port);
            socket.send(packet);
        } catch (Exception e) {
            System.err.println("发送RTP包失败: " + e.getMessage());
        }
    }

    /**
     * 发送注册请求到国标平台
     */
    private void sendRegisterRequest() throws Exception {
        // 创建SIP注册请求
        Address toAddress = addressFactory.createAddress("sip:" + 国标平台Ip + ":" + 国标平台Port);
        Address fromAddress = addressFactory.createAddress("sip:" + deviceId + "@" + localIp + ":" + localPort);
        Address requestUri = addressFactory.createAddress("sip:" + 国标平台Ip + ":" + 国标平台Port);
        
        RegisterRequest registerRequest = messageFactory.createRegisterRequest(requestUri.toString());
        
        // 设置头部信息
        FromHeader fromHeader = headerFactory.createFromHeader(fromAddress, "reg-" + deviceId);
        ToHeader toHeader = headerFactory.createToHeader(toAddress, null);
        CallIdHeader callIdHeader = headerFactory.createCallIdHeader("call-" + UUID.randomUUID());
        CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L, Request.REGISTER);
        ViaHeader viaHeader = headerFactory.createViaHeader(localIp, localPort, "UDP", "via-" + UUID.randomUUID());
        
        registerRequest.setHeader(fromHeader);
        registerRequest.setHeader(toHeader);
        registerRequest.setHeader(callIdHeader);
        registerRequest.setHeader(cSeqHeader);
        registerRequest.addHeader(viaHeader);
        registerRequest.setExpires(headerFactory.createExpiresHeader(3600));
        
        // 发送注册请求
        sipProvider.sendRequest(registerRequest);
        System.out.println("已发送注册请求到国标平台");
    }

    /**
     * 发送INVITE请求建立媒体会话
     */
    private void sendInviteRequest() throws Exception {
        // 创建INVITE请求，建立媒体流传输会话
        // 实际实现需要按照GB28181规范填充SDP信息
        Address toAddress = addressFactory.createAddress("sip:" + 国标平台Ip + ":" + 国标平台Port);
        Address fromAddress = addressFactory.createAddress("sip:" + deviceId + ":" + channelId + "@" + localIp + ":" + localPort);
        Address requestUri = addressFactory.createAddress("sip:" + 国标平台Ip + ":" + 国标平台Port);
        
        InviteRequest inviteRequest = messageFactory.createInviteRequest(requestUri.toString());
        
        // 设置SIP头部（简化版）
        FromHeader fromHeader = headerFactory.createFromHeader(fromAddress, "call-" + UUID.randomUUID());
        ToHeader toHeader = headerFactory.createToHeader(toAddress, null);
        CallIdHeader callIdHeader = headerFactory.createCallIdHeader("call-" + UUID.randomUUID());
        CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L, Request.INVITE);
        ViaHeader viaHeader = headerFactory.createViaHeader(localIp, localPort, "UDP", "via-" + UUID.randomUUID());
        
        inviteRequest.setHeader(fromHeader);
        inviteRequest.setHeader(toHeader);
        inviteRequest.setHeader(callIdHeader);
        inviteRequest.setHeader(cSeqHeader);
        inviteRequest.addHeader(viaHeader);
        
        // 添加SDP信息（媒体描述）
        String sdp = createSdpMessage();
        inviteRequest.setContent(sdp, headerFactory.createContentTypeHeader("application", "sdp"));
        
        // 发送INVITE请求
        sipProvider.sendRequest(inviteRequest);
        System.out.println("已发送INVITE请求建立媒体会话");
    }

    /**
     * 创建SDP消息（媒体描述协议）
     */
    private String createSdpMessage() {
        // 按照GB28181规范创建SDP消息
        StringBuilder sdp = new StringBuilder();
        sdp.append("v=0\r\n");
        sdp.append("o=").append(deviceId).append(" 0 0 IN IP4 ").append(localIp).append("\r\n");
        sdp.append("s=RTSP to GB28181 Stream\r\n");
        sdp.append("c=IN IP4 ").append(localIp).append("\r\n");
        sdp.append("t=0 0\r\n");
        sdp.append("m=video 5060 RTP/AVP 96\r\n"); // 视频流，使用RTP/AVP协议
        sdp.append("a=rtpmap:96 H264/90000\r\n"); // 载荷类型96对应H.264，时钟频率90000
        sdp.append("a=fmtp:96 profile-level-id=42e01f;level-asymmetry-allowed=1\r\n");
        return sdp.toString();
    }

    /**
     * 停止网关
     */
    public void stop() {
        isRunning = false;
        
        if (executor != null) {
            executor.shutdown();
        }
        
        if (grabber != null) {
            try {
                grabber.stop();
                grabber.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        System.out.println("网关已停止");
    }

    // SIP事件处理方法（简化实现）
    @Override public void processRequest(RequestEvent requestEvent) {}
    @Override public void processResponse(ResponseEvent responseEvent) {}
    @Override public void processTimeout(TimeoutEvent timeoutEvent) {}
    @Override public void processIOException(IOExceptionEvent exceptionEvent) {}
    @Override public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {}
    @Override public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {}

    public static void main(String[] args) {
        // 配置参数
        String rtspUrl = "rtsp://example.com/stream"; // 替换为实际RTSP地址
        String localIp = "192.168.1.100"; // 本地IP
        int localPort = 5060; // SIP端口
        String 国标平台Ip = "192.168.1.200"; // 国标平台IP
        int 国标平台Port = 5060; // 国标平台SIP端口
        String deviceId = "31010600001320000001"; // 设备ID（符合GB28181编码规则）
        String channelId = "31010600001320000002"; // 通道ID

        // 创建并启动网关
        RtspToGb28181Gateway gateway = new RtspToGb28181Gateway(
            rtspUrl, localIp, localPort, 国标平台Ip, 国标平台Port, deviceId, channelId);
        gateway.start();

        // 添加关闭钩子
        Runtime.getRuntime().addShutdownHook(new Thread(gateway::stop));
    }
}
